package edu.mercer.sse.plainpdf;

import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;

import org.apache.tika.Tika;

import com.google.common.collect.Range;

import edu.mercer.sse.annotations.Fulfills;
import edu.mercer.sse.error.CriticalException;
import edu.mercer.sse.error.ErrorLoggingVisitor;
import edu.mercer.sse.log.LoggerCustom;
import static com.google.common.base.Preconditions.*;

/**
 * Provide certain file attributes, verification of accessibility.<p>
 *
 * @see FileInformation
 */

public class FileInfo implements FileInformation
{
	/** String - File path supplied by constructor */
	
	private String _filePathStr = "";
	
	/** Path - File Path converted from {@link #_filePathStr} */
	
	private Path _filePathObj = Paths.get("");
	
	/** Range - File path length limits */
	
	private Range<Integer> _filePathRange = Range.closed(0, 170);

	/** Range - File size limits: 100 megabytes */
	
	private Range<Long> _fileSizeRange = Range.closed(0L, 104857600L);
	
	/** Long - File size, length in bytes */
	
	private Long _fileSize = 0L;
	
	
	/**
	 * Constructor.<p>
	 * 
	 * @param filePath - String input file path and name
	 */
	
	public FileInfo( final String filePath )
	{
		checkNotNull( filePath, 
				
				"null file path" );
		
		checkArgument( !filePath.isEmpty(), 
				
				"empty file path" );
		
		checkArgument( _filePathRange.contains(filePath.length()), 
				
				"file path too long" );
	
		_filePathStr = filePath;
				
	}//constructor
	
	
	@Fulfills("FileInformation")
	@Override
	public Boolean isAvailable()
	{
		try
		{		
		
			_filePathObj = Paths.get(_filePathStr);

			if( ! Files.isReadable( _filePathObj ) )
			{ 
				LoggerCustom.obtainLog("FileInfo", Level.FINE).warning(
						"not readable, or not exists: " + _filePathObj );

				return false;
				
			}//if
			
			if( ! Files.isRegularFile( _filePathObj ) )
			{ 
				LoggerCustom.obtainLog("FileInfo", Level.FINE).warning(
						"not a regular file: " + _filePathObj );

				return false;
				
			}//if
			
			if( ! Files.isReadable(_filePathObj) ) 
			{ 
				LoggerCustom.obtainLog("FileInfo", Level.FINE).warning(
						"not readable: " + _filePathObj );

				return false;
				
			}//if

			if( ! _fileSizeRange.contains( Files.size(_filePathObj) ))
			{ 
				LoggerCustom.obtainLog("FileInfo", Level.FINE).warning(
						"file too large: " + _filePathObj );

				return false;				
				
			}//if
			
			_fileSize = Files.size(_filePathObj);
			
		}
		catch( final IOException | IllegalArgumentException err )
		{
			final CriticalException errWrapped = new CriticalException(err);
			
			errWrapped.accept( new ErrorLoggingVisitor() );
		
		}//try
		
		return _fileSize > 0L ? true : false;
		
	}//method
	
	
	@Fulfills("FileInformation")
	@Override
	public String getPath() 
	{
		return _filePathObj.getParent().toString();
	
	}//method

	
	@Fulfills("FileInformation")	
	@Override
	public String getName() 
	{
		return _filePathObj.getFileName().toString();
		
	}//method

	
	@Fulfills("FileInformation")	
	@Override
	public String getLocation() 
	{
		return _filePathObj.toAbsolutePath().toString();
		
	}//method
	

	@Fulfills("FileInformation")	
	@Override
	public Long getSize() 
	{
		return _fileSize;
		
	}//method

	
	@Fulfills("FileInformation")	
	@Override
	public URI getURI() 
	{
		return _filePathObj.toUri();
				
	}//method

		
	@Fulfills("FileInformation")
	@Override
	public String getMimeType()
	{
		String mimeFnd = "";
		
		try
		{
			final Tika mimeDetector = new Tika();
		
			mimeFnd = mimeDetector.detect( _filePathObj.toFile() );
			
		}
		catch( final IOException err )
		{
			final CriticalException errWrapped = new CriticalException(err);
			
			errWrapped.accept( new ErrorLoggingVisitor() );
		
		}//try
		
		return mimeFnd;
		
	}//method

	
	@Fulfills("Object")	
	@Override
	public String toString()
	{
		return getLocation();
		
	}//method
	
	
}//class
